Micron Document
C.S.Burner 🪙 ━►🔥GIT Node

Node / reticulum_mirror / MeshChatX / files / meshchatx / src / frontend / components / tools / RNPathTracePage.vue

Displaying Raw • Download

meshchatx/src/frontend/components/tools/RNPathTracePage.vue 65ca9ddc823fcc2c8f8653c553b944b85db0875f (65ca9ddc) Text, 20.83 KB

T8b949e<!-- SPDX-License-Identifier: 0BSD -->

Tff7b72<templateTff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex flex-col flex-1 overflow-hidden min-w-0 bg-slate-50 dark:bg-zinc-950Ta5d6ff"Tff7b72>
Tff7b72<ToolsPageHeader
Te6edf3icon=Ta5d6ff"Ta5d6ffmap-marker-pathTa5d6ff"
Te6edf3:title=Ta5d6ff"Te6edf3$tTa5d6ff(Ta5d6ff'Ta5d6fftools.rnpath_trace.titleTa5d6ff'Ta5d6ff)Ta5d6ff"
Te6edf3:description=Ta5d6ff"Te6edf3$tTa5d6ff(Ta5d6ff'Ta5d6fftools.rnpath_trace.descriptionTa5d6ff'Ta5d6ff)Ta5d6ff"
Te6edf3accent=Ta5d6ff"Ta5d6ffblueTa5d6ff"
Tff7b72>
Tff7b72<template #actionsTff7b72>
Tff7b72<button
Te6edf3v-if=Ta5d6ff"Ta5d6fftraceResultTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffp-2 text-gray-400 hover:text-indigo-500 dark:hover:text-indigo-400 transition-colors shrink-0Ta5d6ff"
Te6edf3title=Ta5d6ff"Ta5d6ffRefresh TraceTa5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffrunTraceTa5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffrefreshTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-5Ta5d6ff" Te6edf3:class=Ta5d6ff"Ta5d6ff{ Ta5d6ff'Ta5d6ffanimate-spinTa5d6ff'Ta5d6ff: isLoading }Ta5d6ff" Tff7b72/>
Tff7b72</button>
Tff7b72</template>
Tff7b72</ToolsPageHeader>

Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex-1 overflow-y-auto min-w-0Ta5d6ff"Tff7b72>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffp-3 sm:p-4 md:p-6 max-w-5xl mx-auto space-y-4 sm:space-y-6 pb-[max(1rem,env(safe-area-inset-bottom))]Ta5d6ff"
Tff7b72>
T8b949e<!-- main input card -->
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffrounded-lg border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 p-3 sm:p-4 md:p-6Ta5d6ff"
Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex flex-col sm:flex-row items-stretch sm:items-center gap-3Ta5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffrelative flex-1 min-w-0Ta5d6ff"Tff7b72>
Tff7b72<input
Te6edf3v-model=Ta5d6ff"Ta5d6ffdestinationHashTa5d6ff"
Te6edf3type=Ta5d6ff"Ta5d6fftextTa5d6ff"
Te6edf3placeholder=Ta5d6ff"Ta5d6ffinput destination hashTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffw-full pl-4 pr-12 py-3 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-700 rounded-lg text-sm md:text-base font-mono focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-hidden transition-all dark:text-whiteTa5d6ff"
@keyup.Te6edf3enter=Ta5d6ff"Ta5d6ffrunTraceTa5d6ff"
Tff7b72/>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffabsolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none text-gray-400 dark:text-zinc-500Ta5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffidentifierTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-5Ta5d6ff" Tff7b72/>
Tff7b72</div>
Tff7b72</div>
Tff7b72<button
Te6edf3type=Ta5d6ff"Ta5d6ffbuttonTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffw-full sm:w-auto sm:min-w-12 h-12 sm:h-14 px-4 sm:px-0 bg-indigo-600 hover:bg-indigo-500 text-white rounded-lg flex items-center justify-center gap-2 transition active:scale-95 disabled:opacity-50 shrink-0Ta5d6ff"
Te6edf3:disabled=Ta5d6ff"Ta5d6ff!isValidHash || isLoadingTa5d6ff"
Te6edf3title=Ta5d6ff"Ta5d6ffTrace PathTa5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffrunTraceTa5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon
Te6edf3v-if=Ta5d6ff"Ta5d6ff!isLoadingTa5d6ff"
Te6edf3icon-name=Ta5d6ff"Ta5d6ffkeyboard-returnTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffsize-6 sm:size-7Ta5d6ff"
Tff7b72/>
Tff7b72<MaterialDesignIcon v-else Te6edf3icon-name=Ta5d6ff"Ta5d6ffloadingTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-6 animate-spinTa5d6ff" Tff7b72/>
Tff7b72<span Te6edf3class=Ta5d6ff"Ta5d6ffsm:hidden font-semiboldTa5d6ff"Tff7b72>{{ Te6edf3$t("tools.rnpath_trace.trace") }}Tff7b72</span>
Tff7b72</button>
Tff7b72</div>
Tff7b72</div>

T8b949e<!-- results area -->
Tff7b72<div Te6edf3v-if=Ta5d6ff"Ta5d6fftraceResult || isLoading || errorTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffspace-y-6Ta5d6ff"Tff7b72>
T8b949e<!-- loading state -->
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffisLoadingTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffrounded-lg border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 p-8 sm:p-12 flex flex-col items-center justify-center gap-4Ta5d6ff"
Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffrelativeTa5d6ff"Tff7b72>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffw-12 h-12 border-4 border-indigo-200 dark:border-indigo-900/30 border-t-indigo-600 rounded-full animate-spinTa5d6ff"
Tff7b72>Tff7b72</div>
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fftext-sm font-medium text-gray-600 dark:text-gray-400Ta5d6ff"Tff7b72>
{{ Te6edf3$t("tools.rnpath_trace.tracing") }}
Tff7b72</div>
Tff7b72</div>

T8b949e<!-- error state -->
Tff7b72<div
Te6edf3v-else-if=Ta5d6ff"Ta5d6fferrorTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffrounded-lg border border-gray-200 dark:border-zinc-800 border-l-4 border-l-red-500 p-4 sm:p-6 bg-red-50/50 dark:bg-red-900/10Ta5d6ff"
Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex items-start gap-3 text-red-600 dark:text-red-400Ta5d6ff"Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffalert-circleTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-5 md:size-6 shrink-0 mt-0.5Ta5d6ff" Tff7b72/>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffspace-y-1Ta5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fffont-bold text-sm md:text-baseTa5d6ff"Tff7b72>Trace ErrorTff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fftext-xs md:text-sm opacity-90 break-all whitespace-pre-wrap font-monoTa5d6ff"Tff7b72>
{{ error }}
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>

T8b949e<!-- success state -->
Tff7b72<div
Te6edf3v-else-if=Ta5d6ff"Ta5d6fftraceResultTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffspace-y-6 animate-in fade-in slide-in-from-bottom-4 duration-500Ta5d6ff"
Tff7b72>
T8b949e<!-- compact summary bar -->
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffrounded-lg border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 p-1 overflow-hiddenTa5d6ff"
Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex flex-wrap items-center divide-x divide-gray-100 dark:divide-zinc-800Ta5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex-1 min-w-[120px] p-3 md:p-4 flex flex-col items-center text-centerTa5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fftext-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1Ta5d6ff"Tff7b72>
{{ Te6edf3$t("tools.rnpath_trace.total_hops") }}
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fftext-xl md:text-2xl font-black text-indigo-600 dark:text-indigo-400Ta5d6ff"Tff7b72>
{{ traceResult.hops }}
Tff7b72</div>
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex-1 min-w-[120px] p-3 md:p-4 flex flex-col items-center text-centerTa5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fftext-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1Ta5d6ff"Tff7b72>
{{ Te6edf3$t("tools.rnpath_trace.interface") }}
Tff7b72</div>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6fftext-xs md:text-sm font-bold text-gray-700 dark:text-zinc-200 truncate max-w-fullTa5d6ff"
Tff7b72>
{{ traceResult.interface || "None" }}
Tff7b72</div>
Tff7b72</div>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffflex-1 min-w-[120px] p-3 md:p-4 flex flex-col items-center text-center hidden sm:flexTa5d6ff"
Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fftext-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1Ta5d6ff"Tff7b72>
{{ Te6edf3$t("tools.rnpath_trace.next_hop") }}
Tff7b72</div>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6fftext-[10px] md:text-xs font-mono font-bold text-gray-700 dark:text-zinc-300 truncate max-w-fullTa5d6ff"
Tff7b72>
{{ traceResult.next_hop || "N/A" }}
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>

T8b949e<!-- path visualization -->
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffrounded-lg border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 p-4 sm:p-6 md:p-10 lg:p-16Ta5d6ff"
Tff7b72>
T8b949e<!-- Desktop View (Horizontal) -->
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffhidden md:flex items-start justify-center min-w-fit py-4Ta5d6ff"Tff7b72>
Tff7b72<template Te6edf3v-for=Ta5d6ff"Ta5d6ff(node, idx) in traceResult.pathTa5d6ff" Te6edf3:key=Ta5d6ff"Ta5d6ff'Ta5d6ffd-Ta5d6ff'Ta5d6ff + idxTa5d6ff"Tff7b72>
T8b949e<!-- node item -->
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex flex-col items-center group relative w-32 shrink-0Ta5d6ff"Tff7b72>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffw-14 h-14 rounded-2xl flex items-center justify-center transition-all duration-300 shadow-md group-hover:shadow-indigo-500/20 group-hover:scale-110 z-10Ta5d6ff"
Te6edf3:class=Ta5d6ff"Ta5d6ffgetNodeClass(node)Ta5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3:icon-name=Ta5d6ff"Ta5d6ffgetNodeIcon(node)Ta5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-7Ta5d6ff" Tff7b72/>
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffmt-4 text-center px-2 w-fullTa5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fftext-[11px] font-bold text-gray-900 dark:text-white truncateTa5d6ff"Tff7b72>
{{
node.name ||
formatHash(node.hash) ||
(node.type === "unknown"
? Te6edf3$t("tools.rnpath_trace.unknown_hops", { count: node.count })
: "")
}}
Tff7b72</div>
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffnode.interfaceTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6fftext-[9px] text-indigo-500 font-mono font-bold mt-0.5 truncateTa5d6ff"
Tff7b72>
{{ node.interface }}
Tff7b72</div>
Tff7b72</div>

T8b949e<!-- tooltip -->
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffnode.hashTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffabsolute -top-10 left-1/2 -translate-x-1/2 bg-zinc-900 dark:bg-zinc-800 text-white text-[10px] px-2 py-1.5 rounded-lg opacity-0 group-hover:opacity-100 transition-all shadow-xl border border-zinc-700 pointer-events-none font-mono whitespace-nowrap z-20Ta5d6ff"
Tff7b72>
{{ node.hash }}
Tff7b72</div>
Tff7b72</div>

T8b949e<!-- connector -->
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffidx < traceResult.path.length - 1Ta5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffflex-1 min-w-[40px] max-w-[100px] mt-7 h-0.5 relativeTa5d6ff"
Tff7b72>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffabsolute inset-0 bg-indigo-500/30Ta5d6ff"
Te6edf3:class=Ta5d6ff"Ta5d6ff{
Ta5d6ff'Ta5d6ffborder-t-2 border-dashed border-indigo-300 dark:border-indigo-800 bg-transparent h-0Ta5d6ff'Ta5d6ff:
traceResult.path[idx + 1].type === Ta5d6ff'Ta5d6ffunknownTa5d6ff'Ta5d6ff ||
node.type === Ta5d6ff'Ta5d6ffunknownTa5d6ff'Ta5d6ff,
}Ta5d6ff"
Tff7b72>Tff7b72</div>
Tff7b72<div
Te6edf3v-if=Ta5d6ff"
Ta5d6ff traceResult.path[idx + 1].type !== Ta5d6ff'Ta5d6ffunknownTa5d6ff'Ta5d6ff && node.type !== Ta5d6ff'Ta5d6ffunknownTa5d6ff'
Ta5d6ff Ta5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffabsolute right-0 -top-1 w-2 h-2 rounded-full bg-indigo-500 shadow-xs shadow-indigo-500/50Ta5d6ff"
Tff7b72>Tff7b72</div>
Tff7b72</div>
Tff7b72</template>
Tff7b72</div>

T8b949e<!-- Mobile View (Vertical) -->
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffmd:hidden space-y-0Ta5d6ff"Tff7b72>
Tff7b72<template Te6edf3v-for=Ta5d6ff"Ta5d6ff(node, idx) in traceResult.pathTa5d6ff" Te6edf3:key=Ta5d6ff"Ta5d6ff'Ta5d6ffm-Ta5d6ff'Ta5d6ff + idxTa5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex gap-4Ta5d6ff"Tff7b72>
T8b949e<!-- timeline axis -->
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex flex-col items-center w-10 shrink-0Ta5d6ff"Tff7b72>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffw-10 h-10 rounded-xl flex items-center justify-center shadow-md z-10Ta5d6ff"
Te6edf3:class=Ta5d6ff"Ta5d6ffgetNodeClass(node)Ta5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3:icon-name=Ta5d6ff"Ta5d6ffgetNodeIcon(node)Ta5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-5Ta5d6ff" Tff7b72/>
Tff7b72</div>
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffidx < traceResult.path.length - 1Ta5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffw-0.5 flex-1 min-h-[40px] my-1Ta5d6ff"
Te6edf3:class=Ta5d6ff"
Ta5d6ff traceResult.path[idx + 1].type === Ta5d6ff'Ta5d6ffunknownTa5d6ff'Ta5d6ff ||
node.type === Ta5d6ff'Ta5d6ffunknownTa5d6ff'
Ta5d6ff ? Ta5d6ff'Ta5d6ffborder-l-2 border-dashed border-indigo-300 dark:border-indigo-800Ta5d6ff'
Ta5d6ff : Ta5d6ff'Ta5d6ffbg-indigo-500/30Ta5d6ff'
Ta5d6ff Ta5d6ff"
Tff7b72>Tff7b72</div>
Tff7b72</div>

T8b949e<!-- content -->
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex-1 pb-6 pt-1 min-w-0Ta5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6fffont-bold text-sm text-gray-900 dark:text-white truncateTa5d6ff"Tff7b72>
{{
node.name ||
(node.type === "unknown"
? Te6edf3$t("tools.rnpath_trace.unknown_hops", { count: node.count })
: formatHash(node.hash))
}}
Tff7b72</div>
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffnode.hashTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6fftext-[10px] font-mono text-gray-500 dark:text-gray-400 mt-0.5 truncateTa5d6ff"
Tff7b72>
{{ node.hash }}
Tff7b72</div>
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffnode.interfaceTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffinline-flex items-center gap-1 mt-1.5 px-2 py-0.5 bg-indigo-50 dark:bg-indigo-900/20 text-indigo-600 dark:text-indigo-400 rounded-sm text-[9px] font-bold uppercase tracking-widerTa5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffrouter-wirelessTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-3Ta5d6ff" Tff7b72/>
{{ node.interface }}
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</template>
Tff7b72</div>
Tff7b72</div>

T8b949e<!-- action buttons -->
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex flex-col sm:flex-row items-center justify-center gap-3Ta5d6ff"Tff7b72>
Tff7b72<button
Te6edf3class=Ta5d6ff"Ta5d6ffw-full sm:w-auto px-6 py-3 bg-indigo-100 hover:bg-indigo-200 dark:bg-indigo-900/30 dark:hover:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 rounded-2xl font-bold transition flex items-center justify-center gap-2 text-smTa5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffpingDestinationTa5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffradarTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-5Ta5d6ff" Tff7b72/>
{{ Te6edf3$t("tools.rnpath_trace.ping_test") }}
Tff7b72</button>
Tff7b72<button
Te6edf3class=Ta5d6ff"Ta5d6ffw-full sm:w-auto px-6 py-3 bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 hover:bg-gray-50 dark:hover:bg-zinc-800 text-gray-600 dark:text-gray-300 rounded-2xl font-bold transition flex items-center justify-center gap-2 text-smTa5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffcopyDestinationHashTa5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffcontent-copyTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-5Ta5d6ff" Tff7b72/>
{{ Te6edf3$t("common.copy_to_clipboard") }}
Tff7b72</button>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</template>

Tff7b72<scriptTff7b72>
import MaterialDesignIcon from "../MaterialDesignIcon.vue";
import ToastUtils from "../../js/ToastUtils";
import ToolsPageHeader from "./ToolsPageHeader.vue";

export default {
name: "RNPathTracePage",
components: {
MaterialDesignIcon,
ToolsPageHeader,
},
data() {
return {
destinationHash: "",
isLoading: false,
traceResult: null,
error: null,
};
},
computed: {
isValidHash() {
return /^[0-9a-f]{32}$/i.test(this.destinationHash);
},
},
mounted() {
if (this.$route.query.hash) {
this.destinationHash = this.$route.query.hash;
if (this.isValidHash) {
this.runTrace();
}
}
},
methods: {
async runTrace() {
if (!this.isValidHash) return;

this.isLoading = true;
this.error = null;
this.traceResult = null;

try {
const res = await window.api.get(`/api/v1/rnpath/trace/${this.destinationHash}`);
if (res.data.error) {
this.error = res.data.error;
} else {
this.traceResult = res.data;
}
} catch (e) {
console.error(e);
this.error =
e.response?.data?.error ||
e.response?.data?.message ||
"Failed to communicate with the backend handler.";
} finally {
this.isLoading = false;
}
},
getNodeClass(node) {
if (node.type === "local") return "bg-blue-600 text-white";
if (node.type === "destination") return "bg-emerald-600 text-white";
if (node.type === "unknown")
return "bg-gray-100 dark:bg-zinc-800 text-gray-400 dark:text-gray-600 border-2 border-dashed border-gray-200 dark:border-zinc-700 shadow-none";
return "bg-indigo-600 text-white";
},
getNodeIcon(node) {
if (node.type === "local") return "home";
if (node.type === "destination") return "flag-variant";
if (node.type === "unknown") return "dots-horizontal";
return "router-wireless";
},
formatHash(hash) {
if (!hash) return "";
return hash.substring(0, 8) + "...";
},
pingDestination() {
this.$router.push({
name: "ping",
query: {
hash: this.destinationHash,
autostart: "1",
},
});
},
copyDestinationHash() {
if (this.destinationHash) {
navigator.clipboard.writeText(this.destinationHash);
ToastUtils.success(this.$t("common.copied"));
}
},
},
};
Tff7b72</script>

Served by rngit 1.5.2 - Generated in 0.04s